package com.pig4cloud.pigx.contract.lifecycle.started;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mongodb.client.result.UpdateResult;
import com.pig4cloud.pigx.common.customize.mongo.utils.MongoUtils;
import com.pig4cloud.pigx.common.customize.contants.MongoTableNameConstants;
import com.pig4cloud.pigx.common.customize.enums.CommonDictEnum;
import com.pig4cloud.pigx.contract.entity.ContractSymbol;
import com.pig4cloud.pigx.contract.entity.RippleContractSymbolHierarchy;
import com.pig4cloud.pigx.contract.mapper.ContractSymbolMapper;
import com.pig4cloud.pigx.contract.mapper.RippleContractSymbolHierarchyMapper;
import com.pig4cloud.pigx.contract.mapstruct.ContractSymbolHierarchyStruct;
import com.pig4cloud.pigx.contract.mapstruct.ContractSymbolStruct;
import com.pig4cloud.pigx.contract.mongo.entity.ContractOrderBuyMongo;
import com.pig4cloud.pigx.contract.mongo.entity.ContractOrderSaleMongo;
import com.pig4cloud.pigx.contract.mongo.entity.ContractSymbolHierarchyMongo;
import com.pig4cloud.pigx.contract.mongo.entity.ContractSymbolMongo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;

/**
 * 合约服务启动后预热缓存数据
 *
 * @since 2022/8/12 16:12
 */
@Slf4j
@Order(0)
@Component
@AllArgsConstructor
public class ContractWarmUpCache implements ApplicationRunner {

	private final ContractSymbolMapper contractSymbolMapper;
	private final RippleContractSymbolHierarchyMapper contractSymbolHierarchyMapper;

	private final MongoTemplate mongo;

	@Override
	public void run(ApplicationArguments args) throws Exception {
		// 提前创建订单薄
		createOrderBook();
		// 预热币对信息
		symbol();
		// 预热币对头寸信息
		symbolHierarchy();
	}

	/**
	 * 提前创建订单薄
	 *
	 * @since 2022/9/29 12:32
	 */
	private void createOrderBook() {
		// 如果 contract_order_book_buy 不存在，创建
		if (!mongo.collectionExists(ContractOrderBuyMongo.class)) {
			mongo.createCollection(ContractOrderBuyMongo.class);
			log.error("MongoDB-缓存预热-订单薄：{}", MongoTableNameConstants.CONTRACT_ORDER_BOOK_BUY);
		}

		// 如果 contract_order_book_sale 不存在，创建
		if (!mongo.collectionExists(ContractOrderSaleMongo.class)) {
			mongo.createCollection(ContractOrderSaleMongo.class);
			log.error("MongoDB-缓存预热-订单薄：{}", MongoTableNameConstants.CONTRACT_ORDER_BOOK_SALE);
		}
	}

	/**
	 * 预热币对信息
	 *
	 * @since 2022/8/12 16:43
	 */
	private void symbol() {
		// 查询币对信息，更新缓存
		LambdaQueryWrapper<ContractSymbol> lambdaQuery = new LambdaQueryWrapper<ContractSymbol>()
				.eq(ContractSymbol::getStatus, CommonDictEnum.Status.NORMAL.getValue())
				.eq(ContractSymbol::getIsDeleted, CommonDictEnum.IsDeleted.NO.getValue());
		List<ContractSymbol> list = contractSymbolMapper.selectList(lambdaQuery);
		// 如果没有数据，直接删除缓存中的币对信息
		if (CollectionUtils.isEmpty(list)) {
			mongo.dropCollection(ContractSymbolMongo.class);
		}

		List<ContractSymbolMongo> mongoList = ContractSymbolStruct.INSTANCE.list2Mongo(list);

		// 新增/修改
		mongoList.forEach(i -> {
			Criteria criteria = Criteria.where("id").is(i.getId());
			Query query = Query.query(criteria);
			Update update = MongoUtils.getUpdate(i);

			UpdateResult updateResult = mongo.upsert(query, update, ContractSymbolMongo.class);
			if (Objects.isNull(updateResult.getUpsertedId()) && updateResult.getMatchedCount() != 1) {
				log.error("MongoDB-缓存预热-币对信息。更新失败，参数：{}。结果：{}", JSON.toJSONString(i), JSON.toJSONString(updateResult));
				System.exit(0);
			}
		});

		log.error("MongoDB-缓存预热-币对信息。更新成功，条数：{}", list.size());
	}

	/**
	 * 预热币对头寸信息
	 *
	 * @since 2022/8/12 16:43
	 */
	private void symbolHierarchy() {
		// 查询币对头寸信息，更新缓存
		LambdaQueryWrapper<RippleContractSymbolHierarchy> lambdaQuery = new LambdaQueryWrapper<RippleContractSymbolHierarchy>()
				.eq(RippleContractSymbolHierarchy::getIsDeleted, CommonDictEnum.IsDeleted.NO.getValue());
		List<RippleContractSymbolHierarchy> list = contractSymbolHierarchyMapper.selectList(lambdaQuery);
		// 如果没有数据，直接删除缓存中的币对头寸信息
		if (CollectionUtils.isEmpty(list)) {
			mongo.dropCollection(ContractSymbolHierarchyMongo.class);
		}

		List<ContractSymbolHierarchyMongo> mongoList = ContractSymbolHierarchyStruct.INSTANCE.list2Mongo(list);

		// 新增/修改
		mongoList.forEach(i -> {
			Criteria criteria = Criteria.where("id").is(i.getId());
			Query query = Query.query(criteria);
			Update update = MongoUtils.getUpdate(i);

			UpdateResult updateResult = mongo.upsert(query, update, ContractSymbolHierarchyMongo.class);
			if (Objects.isNull(updateResult.getUpsertedId()) && updateResult.getMatchedCount() != 1) {
				log.error("MongoDB-缓存预热-币对头寸信息。更新失败，参数：{}。结果：{}", JSON.toJSONString(i), JSON.toJSONString(updateResult));
				System.exit(0);
			}
		});

		log.error("MongoDB-缓存预热-币对头寸信息。更新成功，条数：{}", list.size());
	}
}
